#include <iostream>
#include <string>
#include <vector>
#include <poll.h> 
#include <sys/time.h>
#include "Log.hpp"
#include "Sock.hpp"

#define FD_NONE -1 

using namespace std ; 





// Poll 使select的位图 + 数组 的参数更新方法变为 结构体数组更新参数的方法 ： 
class PollServer
{
private:

    uint16_t _port ; 
    int _listensock; 
    struct pollfd* _fds; //结构体数组
    int _nfds;           //结构体数组长度       
    int _timeout;        // ？ ？  ？

public:

    static const int nfds = 100 ; 

public: 

    PollServer(const uint16_t& port = 8080)
        :_port(port)
        ,_nfds(nfds)
    {
        //网络基础
        _listensock = Sock::Socket();
        Sock::Bind(_listensock,_port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "%s", "base success");

        //创建并初始化结构体数组
        _fds = new pollfd[_nfds];
        for(int i = 0 ; i < _nfds ; i++)
        {
            _fds[i].fd = FD_NONE ; 
            _fds[i].events = _fds[i].revents = 0 ;
        }        
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN; // ? ? ?   // 普通或优先带数据可读
        _timeout = 1000 ; //  ? ? ? ? ?     // 表示阻塞等待_timeout毫秒

    }

    void Start()
    {
        while (true)
        {
            int n = poll(_fds, _nfds, _timeout);
            switch(n)
            {
                case 0:
                    logMessage(DEBUG, "%s", "time out...");
                    break; 
                case -1:
                    logMessage(WARNING, "select error : %d: %s", errno, strerror(errno));
                    break;
                default:
                    //有文件描述符就绪时
                    HandlerEvent();
                    break;
            }
        }
        

    }

    ~PollServer()
    {
        if(_listensock >= 0)
        {
            close(_listensock);
        }

        if(_fds != nullptr )
        {
            delete[] _fds ; 
        }
    }



private:

    void HandlerEvent()
    {
        for(int i = 0 ; i < _nfds; i++)
        {
            if(_fds[i].fd == FD_NONE)
            {
                continue;
            }

            if(_fds[i].revents & POLLIN)// 系统应答为已读就绪
            {
                //把 Accepter(); 放在if(_fds[i].revents & POLLIN) 条件里是因为，从_listensock里拿有效文件描述符也是一种读操作
                if(_fds[i].fd = _listensock)
                {
                    //如果_listensock 中已有就绪的套接字，就接收 //注意此时接收的套接字是有效，也就是仅仅是与客户成功建立连接产生的套接字
                    Accepter();
                }
                else
                {
                    Recver(i); //与select体系不同的是判断是否有效的方式？ ？ ？  更新有效，就绪的方式 ？ ？ ？ 
                }
            }

        }


    }

    void Accepter()
    {
        string clientip ;
        uint16_t clientport = 0 ; 

        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if(sock < 0)
        {
            logMessage(WARNING, "aceept error");
            return ; 
        }
        //logMessage(DEBUG, "get a new line success : [%s:%d] : %d" , clientip , clientport , sock ); // 为啥报错？ 参数列表不可接收？ 
        int pos = 1 ;
        for(; pos < _nfds ; pos++)
        {
            //找到空位
            if(_fds[pos].fd == FD_NONE)
            {
                break; 
            }

            //判断找到的空位是否合法
            if(pos == _nfds)
            {
                logMessage(WARNING, "%s:%d", "poll server already full , close : %d", sock);
                close(sock);
            }
            else
            {
                _fds[pos].fd= sock ; 
                _fds[pos].events = POLLIN;
            }
        }

    }

    void Recver(int pos)
    {
        //开始读取
        logMessage(DEBUG, "message in : %d" , _fds[pos]); 
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1 , 0); //哎？ 为啥要 sizeof(buffer) - 1 来着  ？？ ？  ？
        if(n > 0)
        {
            buffer[n] = 0 ;
            printf("%s", buffer);
            logMessage(DEBUG, "client[%d]# %s", _fds[pos].fd , buffer);
        }
        else if (n == 0 )
        {
            // n 什么时候为0 ？ 对方文件描述符关闭时 
            logMessage(DEBUG, "client[%d] quit , Server quit too...", _fds[pos].fd);
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE ; 
            _fds[pos].events = 0 ; //events 和 revents 本质是位图还是数值 ？ 本质是位图   
        }
        else
        {
            logMessage(WARNING, "%d sock recv error , %d : %s", _fds[pos].fd, errno, strerror(errno));

        }

    }

    void DebugPrint()
    {
        cout << "fd_arrat[]" ; 
        for(int i = 0 ; i < _nfds ; i++)
        {
            if(_fds[i].fd = FD_NONE)
            {
                continue;
            }
            else
            {
                cout << _fds[i].fd << " ";
            }

            cout << endl ;
        }
    }

};


